/*
 * Created on Aug 18, 2005
 * Copyright 2005 Program of Computer Grpahics, Cornell University
 */
package ray.math;

/**********************************************************************************
 * GENERAL CONTRACT FOR ALL MATH CLASSES.
 * 
 * -- The destination of every method is assumed to be the object the method was
 * called on. For example:
 * 
 * c.add(a,b) means c = a + b.
 * 
 * -- Whenever one operand of a binary operand is missing, it is assumed to be
 * the object the method was called upon. For example:
 * 
 * c.add(a) means c = c + a.
 * 
 ********************************************************************************* 
 * Class for 3d points.
 * 
 * @author arbree Aug 18, 2005 Point3.java Copyright 2005 Program of Computer
 *         Graphics, Cornell University
 */
public class Point3 extends Tuple3 {

	/**
	 * Default constructor. Uses explicit constructor to create a zero vector.
	 */
	public Point3() {
		super(0, 0, 0);
	}

	/**
	 * Copy constructor. This constructor simply calls the explicit constructor
	 * with the necessary fields from the input as parameters.
	 * 
	 * @param newTuple
	 *            The Point3 to copy.
	 */
	public Point3(Point3 newTuple) {
		super(newTuple.x, newTuple.y, newTuple.z);
	}

	/**
	 * The explicit constructor. This is the only constructor with any real code
	 * in it. Values should be set here, and any variables that need to be
	 * calculated should be done here.
	 * 
	 * @param newX
	 *            The x value of the new Point3.
	 * @param newY
	 *            The y value of the new Point3.
	 * @param newZ
	 *            The z value of the new Point3.
	 */
	public Point3(double newX, double newY, double newZ) {
		super(newX, newY, newZ);
	}

	/**
	 * Returns the squared distance from this Point3 to other
	 * 
	 * @param other
	 *            another point
	 * @return the squared distance from this point to the other point
	 */
	public double distanceSquared(Point3 other) {

		double dx = (this.x - other.x);
		double dy = (this.y - other.y);
		double dz = (this.z - other.z);

		return dx * dx + dy * dy + dz * dz;

	}

	/**
	 * Returns the distance from this Point3 to other
	 * 
	 * @param other
	 *            another point
	 * @return the distance
	 */
	public double distance(Point3 other) {

		double dx = (this.x - other.x);
		double dy = (this.y - other.y);
		double dz = (this.z - other.z);

		return Math.sqrt(dx * dx + dy * dy + dz * dz);

	}

	/**
	 * Add a Vector3 to this Point3
	 * 
	 * @param op1
	 *            the Vector3 to add
	 */
	public void add(Vector3 vector) {

		this.x += vector.x;
		this.y += vector.y;
		this.z += vector.z;

	}

	/**
	 * Add a Vector3 to a Point3 and store the result in this Point3
	 * 
	 * @param point
	 *            the input point
	 * @param vector
	 *            the input vector
	 */
	public void add(Point3 point, Vector3 vector) {

		this.x = vector.x + point.x;
		this.y = vector.y + point.y;
		this.z = vector.z + point.z;

	}

	/**
	 * Subtract a Vector3 to this Point3
	 * 
	 * @param op1
	 *            the Vector3 to substract
	 */
	public void sub(Vector3 vector) {

		this.x -= vector.x;
		this.y -= vector.y;
		this.z -= vector.z;

	}

	/**
	 * Subtract a Vector3 from a Point3 and store the result in this Point3
	 * 
	 * @param point
	 *            the input point
	 * @param vector
	 *            the input vector
	 */
	public void sub(Point3 point, Vector3 vector) {

		this.x = point.x - vector.x;
		this.y = point.y - vector.y;
		this.z = point.z - vector.z;

	}

	/**
	 * Add a scaled multiple of a Vector3 to this Point3
	 * 
	 * @param scale
	 *            the input scale
	 * @param vector
	 *            the input vector
	 */
	public void scaleAdd(double scale, Vector3 vector) {

		this.x += scale * vector.x;
		this.y += scale * vector.y;
		this.z += scale * vector.z;

	}

	public Point3(double scale, Point3 start, Point3 end) {
		this.x = start.x + (end.x - start.x) * scale;
		this.y = start.y + (end.y - start.y) * scale;
		this.z = start.z + (end.z - start.z) * scale;
	}

	public static Point3 middlePoint(Point3 pointA, Point3 pointB) {
		return new Point3((pointA.x + pointB.x) / 2, (pointA.y + pointB.y) / 2,
				(pointA.z + pointB.z) / 2);
	}
}
